#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
#include "Log.hpp"
#include "LockGuard.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"

#define BUFFER_SIZE 1024
const static int DefaultSock = -1;
const static int g_backlog = 16;

enum
{
    SOCK_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERROR,
    ACCEPT_ERROR
};

class TCPServer;

class ThreadData
{
public:
    ThreadData(int sockfd, const InetAddr& clientAddr, TCPServer* self)
        : _sockfd(sockfd), _clientAddr(clientAddr), _self(self)
    {}

public:
    int _sockfd;
    InetAddr _clientAddr;
    TCPServer* _self;
};

// 传递一个命令字符串，返回结果字符串
using task_t = std::function<std::string (const std::string&)>; // 命令行功能的函数类型

using task1_t = std::function<std::string(const std::string&, bool&)>; // 翻译功能的函数类型
using task2_t = std::function<void (void)>; // 线程池任务的函数类型

class TCPServer
{
private:
    void Service(int sockfd, const InetAddr& client)
    {
        // 已经获取连接了，这里接收消息
        LOG(DEBUG, "get a new link, info [%s]:%d, fd : %d", client.IP().c_str(), client.Port(), sockfd);
        
        // 拼接一下客户端信息，方便查看
        std::string clientaddr = "[" + client.IP() + ":" + std::to_string(client.Port()) + "]";

        char buffer[BUFFER_SIZE];
        while(true)
        {
            ssize_t readBytes = recv(sockfd, buffer, BUFFER_SIZE - 1, 0);
            if(readBytes > 0)
            {
                buffer[readBytes] = 0;
                std::cout << clientaddr << "-> " << buffer << std::endl;

                // 将收到的消息再发送回客户端

                // 命令行执行
                // std::string echo_string = _func(buffer);


                // 翻译执行
                bool flag = true;
                std::string echo_string = _func(buffer, flag);


                send(sockfd, echo_string.c_str(), echo_string.size(), 0);
            }
            else if(readBytes == 0)
            {
                // 客户端退出，读取到文件末尾
                std::cout << clientaddr << " has exited!" << std::endl;
                break;
            }
            else
            {
                // 读取失败
                LOG(DEBUG, "server receive message error, %s, %d", strerror(errno),  errno);
                break;
            }
        }

        // 服务完毕，需要关闭套接字资源
        close(sockfd);
    }

public:
    // TCPServer(int port, task_t func)
    //     : _port(port), _listenSock(DefaultSock), _func(func)
    // {}

    TCPServer(int port, task1_t func)
        : _port(port), _listenSock(DefaultSock), _func(func)
    {}

    void InitServer()
    {
        // 创建套接字信息
        _listenSock = socket(AF_INET, SOCK_STREAM, 0);
        if(_listenSock < 0)
        {
            LOG(FATAL, "server listenSock error, %s, %d", strerror(errno),  errno);
            exit(SOCK_ERROR);
        }
        // 填充网络信息
        struct sockaddr_in serverAddr;
        memset(&serverAddr, 0, sizeof(struct sockaddr_in));
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(_port);
        serverAddr.sin_addr.s_addr = INADDR_ANY;

        // 绑定
        int n = bind(_listenSock, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr_in));
        if(n < 0)
        {
            LOG(FATAL, "server bind error, %s, %d", strerror(errno),  errno);
            exit(BIND_ERROR);
        }

        // 监听，等待客户端的连接
        n = listen(_listenSock, g_backlog);
        if(n < 0)
        {
            LOG(FATAL, "server listen error, %s, %d", strerror(errno),  errno);
            exit(LISTEN_ERROR);
        }
        LOG(DEBUG, "listen success, sockfd is : %d", _listenSock);

    }


    static void* HandlerSock(void* arg)
    {
        // 线程自己分离
        pthread_detach(pthread_self());

        ThreadData* td = static_cast<ThreadData*>(arg);
        td->_self->Service(td->_sockfd, td->_clientAddr);

        delete td;
        return nullptr;
    }

    void Loop()
    {
        struct sockaddr_in clientAddr;
        socklen_t len = sizeof(struct sockaddr_in);
        while(true)
        {
            // 获取客户端的连接 -- 等到一个用户服务的套接字
            int sockfd = accept(_listenSock, (struct sockaddr*)&clientAddr, &len);
            if(sockfd < 0)
            {
                LOG(FATAL, "server accept error, %s, %d", strerror(errno),  errno);
                continue;
            }

            // 服务
            
            // 命令行执行功能，使用多线程版本
            // pthread_t thread;
            // // 在HandlerSock需要使用到sockfd和clientAddr，但是只能传递一个函数，需要将这两个进行封装
            // // 注意HandlerSock设计成为类内函数，有一个隐含的this指针参数
            // ThreadData* td = new ThreadData(sockfd, InetAddr(clientAddr), this);
            // pthread_create(&thread, nullptr, HandlerSock, td);

            // 翻译功能，使用线程池版本
            task2_t t = std::bind(&TCPServer::Service, this, sockfd, InetAddr(clientAddr));
            ThreadPool<task2_t>::GetInstance()->Push(t);
        }
    }

    ~TCPServer()
    {
        if (_listenSock > DefaultSock)
            ::close(_listenSock);
    }
private:
    int _listenSock;
    uint16_t _port;
    // task_t _func; // 命令行函数

    task1_t _func; // 翻译函数
};